﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using DVK.SP2007.Views;
using Microsoft.SharePoint;
using DVK.SP2007.Resources;
using DVK.SP2007.Constants;
using System.Web.Script.Serialization;
using DVK.SP2007.Moss;
using DVK.SP2007.UniversalClient;
using System.Net.Mime;
using System.Text;
using System.Collections;

namespace DVK.SP2007.Presenters
{
    //TODO: Partially refactored/MVP start up. Need to bring in Repositories as well.
    public class SendToDvkPresenter
    {
        protected const string SessionRecipients = "SessionRecipients";
        private ISendToDvkView _view;
        private SPWeb _web;
        private SPListItem _item;

        /// <summary>
        /// Gets the current item.
        /// </summary>
        /// <value>The current item.</value>
        protected SPListItem CurrentItem
        {
            get
            {
                if (_item == null)
                    _item = _web.GetListItem(_view.ItemUrl);
                return _item;
            }
        }

        public SendToDvkPresenter(ISendToDvkView view, SPWeb web)
        {
            _view = view;
            _web = web;
        }

        //TODO: Use Repositories
        public void Send()
        {
            
            //Message recipients
            var recipients = GetRecipientsFromSession();

            if (!IsValidForSending(recipients))
            {
                _view.ShowErrors();
                return;
            }

            SPListItem newItem = null;
            
            bool redirect = true; //If some operation fails, redirect should not happen and error must be shown
            //Get outbox list
            SPList outboxList = _web.GetListFromUrl(Urls.ListOutbox);

            try
            {
                var targetUrl = InboxOutboxItemHelper.GetValidTargetUrl(_web, outboxList, _view.MessageTitle);

                SPUser messageSender = _web.CurrentUser;
                PersonMetadata messageSenderMetadata = null;

                //Getting nessecary Dvk settings in json form
                DvkSettingsRepository settingsManager = new DvkSettingsRepository(_web);
                string jsonPersonFieldsMapping = settingsManager.GetSetting(Constants.Settings.DvkPersonMetadataFieldsMapping);
                string jsonOrganisationInfo = settingsManager.GetSetting(Constants.Settings.DvkSenderOrganisationInfo);

                //json serializer
                JavaScriptSerializer jsonSerilizer = new JavaScriptSerializer();

                //Getting author and compilators information
                PersonMetadata author = null;
                bool useAuthorAsCompany = false;
                if (_view.UseAuthorAsCompany)
                {
                    useAuthorAsCompany = true;
                }
                List<PersonMetadata> compilators = new List<PersonMetadata>();

                //Getting information from User Information List. To assure we can access metadata, we run with elevated priviledges.
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    //TODO: need to refactor this out of here! 
                    IUserInfoManager<string> mossUserInfoManager =
                        new MossUserInfoManager(new UserInfoFieldMapping(jsonPersonFieldsMapping));

                    //sender information
                    messageSenderMetadata = mossUserInfoManager.GetUserInfo(messageSender.LoginName);

                    //Getting author info
                    if (_view.Author.Accounts.Count > 0)
                    {
                        SPUser spAuthor = _web.EnsureUser(_view.Author.Accounts[0].ToString());
                        author = mossUserInfoManager.GetUserInfo(spAuthor.LoginName);
                    }

                    //getting compilers info
                    foreach (string item in _view.Compilators.Accounts)
                    {
                        SPUser compilatorUser = _web.EnsureUser(item);
                        compilators.Add(mossUserInfoManager.GetUserInfo(compilatorUser.LoginName));
                    }

                    #region WSSUserInfoManager - sample
                    //Use WSSUserInfoManager to make it work with WSS.
                    //IUserInfoManager<int> wssUserInfoManager = 
                    //    new WssUserInfoManager(
                    //            _web, 
                    //            Constants.ListUserInformationUrl, 
                    //            new UserInfoFieldMapping(jsonPersonFieldsMapping)
                    //        );

                    //// implementation details omitted
                    //messageSenderMetadata = wssUserInfoManager.GetUserInfo(messageSender.ID);

                    ////Getting author info
                    //if (peAuthor.Accounts.Count > 0)
                    //{
                    //    SPUser spAuthor = _web.EnsureUser(peAuthor.Accounts[0].ToString());
                    //    author = wssUserInfoManager.GetUserInfo(spAuthor.ID);
                    //}

                    ////getting compilers info
                    //foreach (string item in peCompilators.Accounts)
                    //{
                    //    SPUser compilatorUser = _web.EnsureUser(item);
                    //    compilators.Add(wssUserInfoManager.GetUserInfo(compilatorUser.ID));
                    //}
                    #endregion
                });

                //Getting file data
                SPFile currentFile = CurrentItem.File;
                SPFile newFile = CreateDvkMessageAttachmentInOutbox(outboxList, targetUrl, currentFile);

                //Get SPListItem from file
                newItem = newFile.Item;

                //Map Metadata from old item and from send form to new item 
                //TODO: Check if newItem needs to be input here - only local item id set and thats not used anywhere here. Its also not logical.
                IDvkMessage message =
                    new OutgoingMessageMapper(_web, CurrentItem, newItem)
                    {
                        UseAuthorOrganisation = useAuthorAsCompany,
                        Author = author,
                        Comments = _view.Comments,
                        Compilators = compilators,
                        DocumentLanguage = _view.DocumentLanguage,
                        DocumentType = _view.DocumentType,
                        DocumentVersion = _view.DocumentVersion,
                        DvkFolder = _view.DvkFolder,
                        DvkType = _view.DvkType,
                        Organisation = jsonSerilizer.Deserialize<UnitInfo>(jsonOrganisationInfo),
                        Recipients = recipients,
                        SendDate = (_view.SendDate.HasValue) ? _view.SendDate.Value : DateTime.Now,
                        Sender = messageSenderMetadata,
                        Title = _view.MessageTitle
                    }.Map();

                //Map new message 
                newItem = new OutgoingMessageToListitemMapper(CurrentItem, message, newItem, new AspNetResourceManager()).Map();

                newItem.UpdateOverwriteVersion();
            }
            catch (Exception exc)
            {
                //If exception occurs, we cancel sending, show error message and delete the item, that might have been added to outbox list already
                if (newItem != null)
                {
                    newItem.Delete();
                }
                _view.ShowError(DvkWeb.SendToDVK_ErrorSendFailed, exc.ToString());
                redirect = false;
            }

            //This should not be in try block, weird errors can occur.
            if (redirect)
            {
                _view.RedirectToSource();
            }
        }

        private SPFile CreateDvkMessageAttachmentInOutbox(SPList outboxList, string targetUrl, SPFile currentFile)
        {
            //New item contetTypeId
            var contentTypeId = outboxList.ContentTypes.BestMatch(
                    new SPContentTypeId(ContentTypes.OutboxDocument.ID)
                );

            byte[] data = currentFile.OpenBinary();

            DigiDocFileData newDigiDocFileData = new DigiDocFileData();
            newDigiDocFileData.Contents = data;
            newDigiDocFileData.ContentType = DigiDocFileData.ContentTypeEmbeddedBase64;
            newDigiDocFileData.Size = data.Length;
            newDigiDocFileData.Filename = _view.DocumentName;
            newDigiDocFileData.MimeType = DigiDocFileData.MimeTypeFrom(data, MediaTypeNames.Application.Octet);

            SignedDoc signedDoc = new SignedDoc(newDigiDocFileData);
            data = (new UTF8Encoding()).GetBytes(signedDoc.ToString());

            //Now we start creating the new item. First we setup creation properties.
            var properties = new Hashtable
                                         {
                                             {FieldNames.SPFileContentTypeIdProperty, contentTypeId.ToString()}
                                         };

            //Add new file with creation properties
            SPFile newFile = outboxList.RootFolder.Files.Add(targetUrl, data, properties, true);
            return newFile;
        }

        private bool IsValidForSending(List<SenderReceiverInfo> recipients)
        {
            //Validate input
            //If there are no recipients, there is nobody to send the message
            if (recipients.Count == 0)
            {
                _view.Errors.Add("Recipients", DvkWeb.SendToDVK_ErrorAtLeastOneRecipientIsRequired);
            }

            if (_view.Author.ResolvedEntities.Count == 0)
            {
                _view.Errors.Add("Author", DvkWeb.SendToDVK_ErrorMustEnterAuthor);
            }

            if (_view.Compilators.ResolvedEntities.Count == 0)
            {
                _view.Errors.Add("Compilators", DvkWeb.SendToDVK_ErrorMustEnterCompilators);
            }
            //end validate input

            if (_view.Errors.Count > 0)
            {
                return false;
            }
            return true;
        }


        /// <summary>
        /// Gets recipients list from session.
        /// </summary>
        /// <returns></returns>
        private List<SenderReceiverInfo> GetRecipientsFromSession()
        {
            var recipients = _view.Session[SessionRecipients] as List<SenderReceiverInfo>;
            if (recipients == null)
                recipients = new List<SenderReceiverInfo>();
            return recipients;
        }
        /// <summary>
        /// Sets recipients list to session.
        /// </summary>
        /// <param name="recipients">The recipients.</param>
        private void SetRecipientsToSession(List<SenderReceiverInfo> recipients)
        {
            _view.Session[SessionRecipients] = recipients;
        }
    }
}
